package com.basic.business.rpaServer;

import com.basic.business.common.constants.Constants;
import com.basic.business.common.enums.PstStatus;
import com.basic.business.common.exception.OrdersException;
import com.basic.business.common.redis.RedisCacheUtils;
import com.basic.business.common.utils.DateUtils;
import com.basic.business.common.utils.DingTalkUtils;
import com.basic.business.common.utils.FileUtils;
import com.basic.business.common.utils.StringUtils;
import com.basic.business.common.utils.kmUtil.KmTagsUtils;
import com.basic.business.img.domain.TImagesInfo;
import com.basic.business.img.service.ITImagesInfoService;
import com.basic.business.log.service.ITOrdersLogService;
import com.basic.business.memoRelation.domain.TOrdersMemoRelation;
import com.basic.business.order.domain.TOrdersDetail;
import com.basic.business.order.domain.TOrdersMain;
import com.basic.business.order.domain.TOrdersStatus;
import com.basic.business.order.service.ITOrdersStatusService;
import com.basic.business.order.service.ITOrdersTimeLineService;
import com.basic.business.pathRel.domain.TPathRel;
import com.basic.business.prodRel.domain.TProdRelDetails;
import com.basic.business.redis.domain.TOrdersDetailRedis;
import com.basic.business.redis.domain.TOrdersMainRedis;
import com.basic.business.redis.domain.TOrdersMergeRedis;
import com.basic.business.shift.domain.TShiftMgmt;
import com.basic.business.smb.domain.TSmbMgmt;
import com.basic.business.store.domain.TStoreMgmt;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * 多线程处理订单
 */
@Slf4j
@Component
public class MultiThreadProcessor {

    @Resource
    private ITImagesInfoService imgService;

    @Resource
    private ITOrdersLogService logService;

    @Resource
    private ITOrdersStatusService statusService;

    @Resource
    private ITOrdersTimeLineService timeLineService;

    @Resource(name = "orderExecutor")
    private ExecutorService orderExecutor;

    /**
     * 入口
     */
    public void init(TOrdersMain main, List<TOrdersDetail> details){

        try {

            ExecutorService executor = orderExecutor;

            long mainSid = main.getSid();

            TOrdersStatus status = TOrdersStatus.createTOrdersStatus(main);

            TOrdersMainRedis mainRedis = RedisCacheUtils.getCacheObject(Constants.ORDERS_REDIS_KEY + mainSid);

            List<TOrdersDetail> filterDetails = filterData(mainSid, details);
            if (CollectionUtils.isEmpty(filterDetails)) return;
            // 提交所有任务
            List<Future<Boolean>> futures = new ArrayList<>();
            for (TOrdersDetail detail : filterDetails) {
                futures.add(executor.submit(() -> processData(mainSid, detail, mainRedis)));
            }

            boolean allSuccess = true;

            // 检查每个任务结果
            for (Future<Boolean> future : futures) {
                try {
                    if (!future.get()) { // 任一失败则整体失败
                        allSuccess = false;
                        break;
                    }
                } catch (ExecutionException | InterruptedException e) {
                    log.error("任务执行异常：{}", e.getMessage());
                    allSuccess = false;
                    break;
                }
            }
            // 根据结果更新状态
            if (allSuccess) {
                String tagsStr = KmTagsUtils.updateExclusiveTag(mainSid, main.getTags(), KmTagsUtils.TAG_NO_PROCESSING);
                mainRedis.getDetailList().forEach(detailR -> detailR.setPst(PstStatus.AUTO_FINISHED.name()));
                // 更新主订单自动处理状态为【自动处理】
                status.setOrderStatus(PstStatus.AUTO_FINISHED.name());
                statusService.insertPst(status);
                if (StringUtils.isNotBlank(tagsStr)) {
                    logService.insert(mainSid, mainSid, String.format("执行【全26编码】策略成功；%s", tagsStr));
                }
            } else {
                String tagsStr = KmTagsUtils.updateExclusiveTag(mainSid, main.getTags(), KmTagsUtils.TAG_NORMAL_PROCESSING);
                mainRedis.getDetailList().forEach(detailR -> detailR.setPst(PstStatus.MANUAL.name()));
                // 更新主订单自动处理状态为【人工处理】
                status.setOrderStatus(PstStatus.MANUAL.name());
                statusService.insertPst(status);
                logService.insert(mainSid, mainSid, String.format("执行【全26编码】策略失败；%s", tagsStr));
            }

            RedisCacheUtils.setCacheObject(Constants.ORDERS_REDIS_KEY + mainSid, mainRedis);

            renameSmbPath(mainRedis);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 过滤订单详情数据，返回符合特定状态的订单详情列表
     *
     * @param mainSid 主订单ID，用于从Redis中获取主订单信息
     * @param details 待过滤的订单详情列表
     * @return List<TOrdersDetail> 过滤后的订单详情列表，仅包含状态为UNPROCESSED或MANUAL且detailSid匹配的订单
     */
    public List<TOrdersDetail> filterData(long mainSid, List<TOrdersDetail> details) {
        // 从Redis缓存中获取主订单信息
        TOrdersMainRedis mainRedis = RedisCacheUtils.getCacheObject(Constants.ORDERS_REDIS_KEY + mainSid);
        List<TOrdersDetail> result = new ArrayList<>();

        // 如果主订单信息不存在，直接返回空结果
        if (mainRedis == null) {
            return result;
        }

        // 获取主订单关联的详情列表（Redis缓存版本）
        List<TOrdersDetailRedis> detailList = mainRedis.getDetailList();

        // 遍历输入详情列表，筛选符合条件的数据
        details.forEach(detail -> {
            // 检查是否存在匹配的Redis详情记录：状态为UNPROCESSED或MANUAL且detailSid相同
            boolean isMatch = detailList.stream()
                    .anyMatch(detailRedis ->
                            StringUtils.containsAny(detailRedis.getPst(), PstStatus.UNPROCESSED.name(), PstStatus.MANUAL.name()) &&
                                    (detail.getDetailSid() == detailRedis.getDetailSid())
                    );
            if (isMatch) {
                result.add(detail);
            }
        });

        return result;
    }

    /**
     * 处理订单数据
     */
    public boolean processData(long mainSid, TOrdersDetail detail, TOrdersMainRedis mainRedis) {
        try {
            // 明细订单sid
            long detailSid = detail.getDetailSid();
            // 商品关系编码
            String sk = detail.getOuterSkuId();
            // 订单数量
            int orderNum = detail.getNum();

            long id = detail.getId();

            // 获取商品对应的文件信息
            int retryCount = 0;
            List<TProdRelDetails> prodRelList = RedisCacheUtils.getCacheObject(Constants.PROD_REL_REDIS_KEY + sk);
            while (retryCount < 3 && CollectionUtils.isEmpty(prodRelList)) {
                prodRelList = RedisCacheUtils.getCacheObject(Constants.PROD_REL_REDIS_KEY + sk);
                if (CollectionUtils.isEmpty(prodRelList)) {
                    Thread.sleep(100); // 短暂等待
                    retryCount++;
                }
            }

            if (CollectionUtils.isEmpty(prodRelList)) {
                // 异步发送钉钉消息
                CompletableFuture.runAsync(() -> DingTalkUtils.send(String.format("商品关系编码：%s，内部单号：%s，未找到对应的商品关系信息", sk, mainRedis.getShortId()), "RPA", ""));
                throw new OrdersException(String.format("商品关系编码：%s，内部单号：%s，未找到对应的商品关系信息", sk, mainRedis.getShortId()));
            }

            prodRelList.forEach(prodRel -> handleProdRel(mainSid, detailSid, id, prodRel, orderNum, mainRedis));
        } catch (Exception e) {
            log.error("处理订单数据失败：{}", e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * 商品关系处理
     */
    public void handleProdRel(long mainSid, long detailSid, long id, TProdRelDetails prodRel, int orderNum, TOrdersMainRedis mainRedis) {
        String path = null;
        try {
            // 文件id
            String imgId = prodRel.getImgId();
            // 材质id
            String matId = prodRel.getImgMaterial();
            // 店铺id
            String shopId = prodRel.getShopId();
            // 数量
            int num = prodRel.getImgNum();
            // 尺寸
            String dim = prodRel.getImgDimensions();
            // 获取订单中的店铺名称
            String kmShopName = mainRedis.getShopName();
            // 获取订单中的内部单号
            String shortId = mainRedis.getShortId();

            // 获取路径信息
            TPathRel pathRel = RedisCacheUtils.getCacheObject(Constants.PATH_REL_REDIS_KEY + matId);

            if (pathRel == null) {
                // 异步发送钉钉消息
                CompletableFuture.runAsync(() -> DingTalkUtils.send(String.format("材质ID：%S，内部单号：%s，未找到对应的路径关系信息；", matId, mainRedis.getShortId()), "RPA", ""));
                throw new OrdersException(String.format("材质ID：%S，内部单号：%s，未找到对应的路径关系信息；", matId, mainRedis.getShortId()));
            }
            // 拷图格式
            String imgFormat = pathRel.getPathFormat();
            if (StringUtils.isNull(imgFormat)) {
                // 异步发送钉钉消息
                CompletableFuture.runAsync(() -> DingTalkUtils.send(String.format("材质ID：%S，内部单号：%s，未找到对应的拷图关系信息；", matId, mainRedis.getShortId()), "RPA", ""));
               throw new OrdersException(String.format("材质ID：%S，内部单号：%s，未找到对应的拷图关系信息；", matId, mainRedis.getShortId()));
            }

            // 材质名称
            String matName = pathRel.getMatName();

            // 获取打包路径
            path = generatePackPath(pathRel, shopId, kmShopName, shortId, mainRedis);
            // 根据生成的打包路径创建文件夹
            FileUtils.createDirectories(path);

            // 获取下载文件路径
            List<String> filePaths = getDownloadFilePath(imgId, imgFormat);

            packFile(mainSid, detailSid, id, filePaths, orderNum, num, dim, matName, path, mainRedis, imgId);

        } catch (Exception e) {
            // 删除打包路径
            FileUtils.deleteFromSmb(path + "/", mainRedis.getShortId());
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 生成打包路径
     */
    public String generatePackPath(TPathRel pathRel, String shopId, String kmShopName, String shortId, TOrdersMainRedis mainRedis) {
        try {
            // 获取路径
            String path = pathRel.getPath();
            // 拆分后的路径
            String[] parts = splitPath(path);

            // 获取店铺信息

            int retryCount = 0;
            TStoreMgmt storeMgmt = RedisCacheUtils.getCacheObject(Constants.STORE_REDIS_KEY + shopId);
            while (retryCount < 3 && storeMgmt == null) {
                storeMgmt = RedisCacheUtils.getCacheObject(Constants.STORE_REDIS_KEY + shopId);
                if (storeMgmt == null) {
                    Thread.sleep(100); // 短暂等待
                    retryCount++;
                }
            }

            if (storeMgmt == null) {
                // 异步发送钉钉消息
                CompletableFuture.runAsync(() -> DingTalkUtils.send(String.format("店铺ID：%s，内部单号：%s，未找到对应的店铺信息", shopId, mainRedis.getShortId()), "RPA", ""));
                throw new OrdersException(String.format("店铺ID：%s，内部单号：%s，未找到对应的店铺信息", shopId, mainRedis.getShortId()));
            }

            // 店铺对应的事业部
            String divName = storeMgmt.getDivName();

            // 当前日期路径
            String datePath = DateUtils.getDatePath();

            // 文件存储路径
            TSmbMgmt smbMgmt = RedisCacheUtils.getCacheObject(Constants.SMB_REDIS_KEY);
            // smb路径
            String smbPath = smbMgmt.getSmbPath();

            // 远程SMB完成路径
            String remotePath = smbPath + datePath + parts[0] + "/" + getShift() + "/" + divName + parts[1] + "/" + kmShopName + "/" + shortId + "+" + kmShopName;
            System.out.println(remotePath);
            // 构建远程路径
            return remotePath + pathAddition(mainRedis);
        } catch (Exception e) {
            // 异步发送钉钉消息
            CompletableFuture.runAsync(() -> DingTalkUtils.send(String.format("生成打包路径失败：内部单号：%s", mainRedis.getShortId()), "RPA", ""));
            throw new RuntimeException(String.format("生成打包路径失败：内部单号：%s", shortId), e);
        }
    }

    /**
     * 拆分路径
     */
    public static String[] splitPath(String path){
        String[] parts = path.split("/", 3); // 使用正斜杠分割，限制分割次数为3
        String part1 = "/" + parts[1]; // 第一部分
        String part2 = "/" + parts[2]; // 第二部分
        return new String[]{part1,part2};
    }

    /**
     * 判断班次
     */
    public static String getShift(){
        // 获取当前时间
        LocalTime currentTime = LocalTime.now();
        // 获取班次信息
        List<TShiftMgmt> shiftMgmtList = RedisCacheUtils.getCacheObject(Constants.SHIFT_REDIS_KEY);
        // 遍历班次，判断当前时间属于哪个班次
        for (TShiftMgmt shift : shiftMgmtList) {
            // 处理跨天班次的情况
            if (shift.getEndTime().isBefore(shift.getStartTime())) {
                // 如果班次结束时间早于开始时间，说明班次跨越午夜
                if (currentTime.isAfter(shift.getStartTime()) || currentTime.isBefore(shift.getEndTime())) {
                    return shift.getShiftName();
                }
            } else {
                // 普通班次
                if (currentTime.isAfter(shift.getStartTime()) && currentTime.isBefore(shift.getEndTime())) {
                    return shift.getShiftName();
                }
            }
        }
        return "当前时间不属于任何班次";
    }

    /**
     * 根据拷图格式获取下载文件路径
     */
    public List<String> getDownloadFilePath(String imgId, String imgFormat) {
        List<String> paths = new ArrayList<>();
        try {
            // 获取文件信息
            TImagesInfo imagesInfo = imgService.getNormalImgInfoById(imgId);
            if (imagesInfo != null) {
                if (StringUtils.contains(imgFormat, ".jpg")) {
                    paths.add(imagesInfo.getBucketUrl() + imagesInfo.getImgJpgPath());
                }
                if (StringUtils.contains(imgFormat, ".png")) {
                    paths.add(imagesInfo.getBucketUrl() + imagesInfo.getImgPngPath());
                }
                if (StringUtils.contains(imgFormat, ".source")) {
                    paths.add(imagesInfo.getBucketUrl() + imagesInfo.getImgSourcePath());
                }
            } else {
                throw new RuntimeException("获取文件信息为空");
            }
        } catch (Exception e) {
            throw new RuntimeException("根据拷图格式获取下载文件路径失败：" + e.getMessage());
        }
        return paths;
    }


    /**
     * 文件打包
     */
    public void packFile(long mainSid, long detailSid, long id, List<String> filePaths, int orderNum, int num, String dim, String matName, String path, TOrdersMainRedis mainRedis, String imgId) {
        // 存储文件真实路径
        Set<String> filePathSet = new HashSet<>();
        filePaths.forEach(v -> {
            // 根据value获取后缀名
            String suffix = "." + StringUtils.substringAfterLast(v, ".");
            String fileName = String.format("%d张 %s %s%s", orderNum * num, dim, matName, suffix);
            try {
                // 真实文件名称
                String realFileName = FileUtils.downloadFileFromHttpToSmb(v, path + "/" + fileName, imgId, mainSid);
                // 写日志
                logService.insert(mainSid, detailSid, String.format("执行【全26编码】策略成功；文件路径：%s", realFileName));

                filePathSet.add(realFileName);

            } catch (Exception e) {
                // 写日志
                throw new RuntimeException(e.getMessage());
            }
        });

        // 将路径更新到Redis中
        Optional.ofNullable(mainRedis.getDetailList())
                .ifPresent(details -> details.stream()
                        .filter(detail -> detail.getDetailSid() == detailSid & detail.getId() == id)
                        .forEach(detail -> detail.setSmbPath(String.join(",", filePathSet))));
    }

    /**
     * 处理订单主信息，并根据订单备注生成远程路径。
     *
     * 该函数从Redis缓存中获取订单备注列表，并根据订单主信息中的合单信息，
     * 匹配备注内容，生成对应的远程路径。
     *
     * @param mainRedis 包含订单主信息的对象，其中包含合单信息列表。
     */
    public String pathAddition(TOrdersMainRedis mainRedis){
        // 从Redis缓存中获取订单备注列表
        List<TOrdersMemoRelation> memos = RedisCacheUtils.getCacheObject(Constants.MEMO_RELATION_REDIS_KEY);

        // 初始化用于构建远程路径的StringBuilder
        StringBuilder remotePathBuilder = new StringBuilder();

        // 检查订单备注列表是否为空
        if (memos != null) {
            // 遍历合单信息，匹配备注内容并生成远程路径
            mainRedis.getMergeList().stream().filter(merge -> StringUtils.equals(merge.getSysStatus(), "WAIT_AUDIT")).forEach(merge -> {
                String memo = merge.getSellerMemo();

                // 遍历订单备注列表，查找匹配的备注并追加对应的远程路径
                memos.forEach(memo1 -> {
                    if (StringUtils.contains(memo, memo1.getSellerMemo())) {
                        remotePathBuilder.append(memo1.getSmbPath());
                    }
                });
            });
        }
        return remotePathBuilder.toString();

    }


    /**
     * 路径修改
     */
    public void renameSmbPath(TOrdersMainRedis mainRedis) {
        // 从Redis缓存中获取订单备注列表
        List<TOrdersMemoRelation> memos = RedisCacheUtils.getCacheObject(Constants.MEMO_RELATION_REDIS_KEY);

        // 检查detailList是否为空
        List<TOrdersDetailRedis> detailList = mainRedis.getDetailList() != null ?
                mainRedis.getDetailList().stream()
                        .filter(detail -> StringUtils.equals(detail.getSysStatus(), "WAIT_AUDIT")
                                && StringUtils.equals(detail.getPst(), PstStatus.AUTO_FINISHED.name()))
                        .collect(Collectors.toList()) :
                Collections.emptyList();

        // 检查mergeList是否为空
        List<TOrdersMergeRedis> mergeList = mainRedis.getMergeList() != null ?
                mainRedis.getMergeList().stream()
                        .filter(merge -> StringUtils.equals(merge.getSysStatus(), "WAIT_AUDIT"))
                        .collect(Collectors.toList()) :
                Collections.emptyList();

        // 遍历合单信息，匹配备注内容并生成远程路径
        mergeList.forEach(merge -> {
            String memo = merge.getSellerMemo();

            memos.forEach(memo1 -> {
                String smbPath = memo1.getSmbPath();
                String sellerMemo = memo1.getSellerMemo();
                if (StringUtils.contains(memo, sellerMemo)) {
                    detailList.forEach(detail -> {
                        String smbPathRedis = detail.getSmbPath();
                        if (detail.getDetailSid() == merge.getMergeSid() && !StringUtils.contains(smbPathRedis, smbPath)) {
                            String smbPathP = smbPathProcess(smbPathRedis);
                            String smbPathAfter = smbPathAfter(smbPathRedis);
                            String oldPath = smbPathP + "/";
                            String newPath = smbPathP + smbPath + "/";
                            try {
                                FileUtils.renameSmbPath(smbPathP + "/", smbPathP + smbPath + "/");
                                detail.setSmbPath(smbPathP + smbPath + "/" + smbPathAfter);
                                // 写日志
                                logService.insert(mainRedis.getSid(), detail.getDetailSid(), String.format("执行【%s】策略成功；文件路径：%s", sellerMemo, detail.getSmbPath()));
                            } catch (Exception e) {
                                // 处理异常，例如记录日志或抛出自定义异常
                                log.error("文件路径修改失败：系统单号：{}；旧路径：{}，新路径：{}", mainRedis.getSid(), oldPath, newPath);
                            }
                        }
                    });
                }
            });
        });
        RedisCacheUtils.setCacheObject(Constants.ORDERS_REDIS_KEY + mainRedis.getSid(), mainRedis);
    }

    /**
     * smb路径处理
     */
    public String smbPathProcess(String smbPath){
        return smbPath.substring(0, smbPath.lastIndexOf('/'));
    }

    /**
     * 获取smb路径最后一个/后边的内容
     */
    public String smbPathAfter(String smbPath){
        return smbPath.substring(smbPath.lastIndexOf('/') + 1);
    }

}
